package com.meeting.meetingroom_api.service.impl;

import com.meeting.meetingroom_api.constants.ErrorMessages;
import com.meeting.meetingroom_api.dto.*;
import com.meeting.meetingroom_api.entity.MeetingRoom;
import com.meeting.meetingroom_api.entity.Booking;
import com.meeting.meetingroom_api.entity.User;
import com.meeting.meetingroom_api.enums.RoomStatus;
import com.meeting.meetingroom_api.enums.BookingStatus;
import com.meeting.meetingroom_api.enums.UserRole;
import com.meeting.meetingroom_api.repository.BookingRepository;
import com.meeting.meetingroom_api.repository.MeetingRoomRepository;
import com.meeting.meetingroom_api.repository.UserRepository;
import com.meeting.meetingroom_api.service.MeetingRoomService;
import com.meeting.meetingroom_api.specification.BookingSpecification;
import com.meeting.meetingroom_api.specification.MeetingRoomSpecification; // We'll create this
import jakarta.persistence.EntityNotFoundException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;

@Service
public class MeetingRoomServiceImpl implements MeetingRoomService {

    private final MeetingRoomRepository meetingRoomRepository;
    private final BookingRepository bookingRepository;
    private final UserRepository userRepository;

    @Autowired
    public MeetingRoomServiceImpl(MeetingRoomRepository meetingRoomRepository, BookingRepository bookingRepository, UserRepository userRepository) {
        this.meetingRoomRepository = meetingRoomRepository;
        this.bookingRepository = bookingRepository;
        this.userRepository = userRepository;
    }

    @Override
    @Transactional
    public MeetingRoomDto createMeetingRoom(MeetingRoomCreateDto createDto) {
        if (meetingRoomRepository.findByName(createDto.getName()).isPresent()) {
            throw new IllegalArgumentException(String.format(ErrorMessages.MEETING_ROOM_NAME_EXISTS, createDto.getName()));
        }
        MeetingRoom meetingRoom = new MeetingRoom();
        BeanUtils.copyProperties(createDto, meetingRoom);

        // Set defaults if not provided
        if (createDto.getOperatingStartTime() == null) {
            meetingRoom.setOperatingStartTime(LocalTime.of(8, 0));
        }
        if (createDto.getOperatingEndTime() == null) {
            meetingRoom.setOperatingEndTime(LocalTime.of(21, 0));
        }
        meetingRoom.setStatus(RoomStatus.available); // Default status

        MeetingRoom savedRoom = meetingRoomRepository.save(meetingRoom);
        return convertToDto(savedRoom);
    }

    @Override
    public MeetingRoomDto getMeetingRoomById(Integer roomId) {
        MeetingRoom room = meetingRoomRepository.findById(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));
        return convertToDto(room);
    }

    @Override
    public MeetingRoomDto getMeetingRoomByIdAndPeriod(Integer roomId, MeetingRoomQueryDto queryDto) {
        MeetingRoom room = meetingRoomRepository.findById(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));
        // 为会议室计算在指定时间段的状态
        if (queryDto.getDesiredStartTime() != null && queryDto.getDesiredEndTime() != null) {
            // 查询指定时间段内的预订情况
            List<BookingStatus> validStatuses = Arrays.asList(
                    BookingStatus.confirmed,
                    BookingStatus.pending_payment,
                    BookingStatus.in_progress
            );
            //获取指定时间段的会议室对应的订单
            List<Booking> overlappingBookings = bookingRepository.findOnePeriodBookings(
                    roomId,
                    queryDto.getDesiredStartTime(),
                    queryDto.getDesiredEndTime(),
                    validStatuses
            );

            // 进行状态计算
            Map<Integer, Booking> earliestOverlappingBookings = overlappingBookings.stream()
                    .collect(Collectors.toMap(
                            b -> b.getRoom().getRoomId(),
                            b -> b,
                            (existing, replacement) -> existing.getStartDatetime().isBefore(replacement.getStartDatetime()) ?
                                    existing : replacement
                    ));

            // 设置计算状态
                Booking earliestBooking = earliestOverlappingBookings.get(roomId);
                room.setCalculatedStatus(calculateStatus(room, earliestBooking));

        }
     return  convertToDto(room);
    }

    @Override
    public MeetingRoomDto getMeetingRoomByName(String name) {
        MeetingRoom room = meetingRoomRepository.findByName(name)
                .orElseThrow(() -> new EntityNotFoundException("找不到会议室，名称: " + name));
        return convertToDto(room);
    }

    @Override
    public List<MeetingRoomDto> getAllMeetingRooms() {
        return meetingRoomRepository.findAll().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    public Page<MeetingRoomDto> findMeetingRooms(MeetingRoomQueryDto queryDto, Pageable pageable) {
        Specification<MeetingRoom> spec = MeetingRoomSpecification.findByCriteria(queryDto);
        Page<MeetingRoom> meetingRoomsPage = meetingRoomRepository.findAll(spec, pageable);
        // 确保时间段为未来时间
        LocalDateTime now = LocalDateTime.now();
        if (queryDto.getDesiredStartTime() != null &&
                queryDto.getDesiredEndTime() != null &&
                (queryDto.getDesiredStartTime().isBefore(now) || queryDto.getDesiredEndTime().isBefore(now))) {
            throw new IllegalArgumentException("查询时间段必须为未来时间");
        }
        if (queryDto.getDesiredStartTime() != null && queryDto.getDesiredEndTime() != null) {
            // 获取所有会议室ID
            List<Integer> roomIds = meetingRoomsPage.getContent().stream()
                    .map(MeetingRoom::getRoomId)
                    .toList();

            // 有效订单状态列表
            List<BookingStatus> validStatuses = Arrays.asList(
                    BookingStatus.confirmed,
                    BookingStatus.pending_payment,
                    BookingStatus.in_progress
            );
            //需求是这样的：
            // 如果要查询的时间段没有会议室对应的订单，会议室原本是维修还是维修，不是维修就空闲。
            // 如果要查询的时间段在某一个订单的时间段内或者有某个订单的时间段一部分在这个时间段内，那么此时会议室为使用中in_use。
            // 如果要查询的时间段包含了多个订单的时间段，就看哪一个订单的时间段在要查询时间段的前面，如果最前面的订单为confirmed，会议为被预订booked.如果是pending_payment，会议室locked
            List<Booking> overlappingBookings = bookingRepository.findPeriodBookings(
                    roomIds,
                    queryDto.getDesiredStartTime(),
                    queryDto.getDesiredEndTime(),
                    validStatuses
            );
            // 按会议室ID分组，并获取每个会议室最早重叠预订
            Map<Integer, Booking> earliestOverlappingBookings = overlappingBookings.stream()
                    .collect(Collectors.toMap(
                            b -> b.getRoom().getRoomId(),
                            b -> b,
                            (existing, replacement) -> existing.getStartDatetime().isBefore(replacement.getStartDatetime()) ?
                                    existing : replacement // 保留开始时间更早的预订
                    ));

            // 计算状态并过滤结果
            List<MeetingRoom> filteredRooms = new ArrayList<>();
            for (MeetingRoom room : meetingRoomsPage.getContent()) {
                Booking earliestBooking = earliestOverlappingBookings.get(room.getRoomId());
                RoomStatus calculatedStatus = calculateStatus(room, earliestBooking);
                room.setCalculatedStatus(calculatedStatus);
                
                // 如果查询参数中指定了status=available，则过滤掉实际不可用的会议室
                if (queryDto.getStatus() == RoomStatus.available || 
                    (queryDto.getStatusList() != null && queryDto.getStatusList().contains(RoomStatus.available))) {
                    // 只保留计算状态为available的会议室
                    if (calculatedStatus == RoomStatus.available) {
                        filteredRooms.add(room);
                    }
                } else {
                    // 如果没有指定available状态过滤，保留所有会议室
                    filteredRooms.add(room);
                }
            }
            
            // 重新构建分页结果
            int start = Math.min((int) pageable.getOffset(), filteredRooms.size());
            int end = Math.min(start + pageable.getPageSize(), filteredRooms.size());
            List<MeetingRoom> pageContent = filteredRooms.subList(start, end);
            
            Page<MeetingRoom> filteredPage = new PageImpl<>(pageContent, pageable, filteredRooms.size());
            return filteredPage.map(this::convertToDto);
        }

        return meetingRoomsPage.map(this::convertToDto);
    }

    private RoomStatus calculateStatus(MeetingRoom room, Booking earliestBooking) {
        // 维护状态优先，不被覆盖
        if (room.getStatus() == RoomStatus.maintenance) {
            return RoomStatus.maintenance;
        }
        
        if (earliestBooking == null) {
            // 没有重叠的预订，返回available
            return RoomStatus.available;
        } else {
            // 根据最早重叠预订的状态确定会议室状态
            return switch (earliestBooking.getStatus()) {
                case in_progress -> RoomStatus.in_use;
                case pending_payment -> RoomStatus.locked;
                case confirmed -> RoomStatus.booked;
                default -> RoomStatus.available;
            };
        }
    }

    @Override
    @Transactional
    public MeetingRoomDto updateMeetingRoom(Integer roomId, MeetingRoomUpdateDto updateDto) {
        MeetingRoom room = meetingRoomRepository.findById(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));
        if (room.getStatus() != RoomStatus.available && room.getStatus() != RoomStatus.maintenance) {
            throw new IllegalStateException(String.format(ErrorMessages.ROOM_STATUS_NOT_ALLOW_MODIFY, room.getStatus()));
        }
        // 名称冲突检查
        if (updateDto.getName() != null && !updateDto.getName().equals(room.getName())) {
            meetingRoomRepository.findByName(updateDto.getName()).ifPresent(existingRoom -> {
                if (!existingRoom.getRoomId().equals(roomId)) {
                    throw new IllegalArgumentException(String.format(ErrorMessages.ROOM_NAME_CONFLICT, updateDto.getName()));
                }
            });
            room.setName(updateDto.getName());
        }
        // 处理设备字段（独立更新，替换原 hasMultimedia）
        if (updateDto.getHasProjector() != null) room.setHasProjector(updateDto.getHasProjector());
        if (updateDto.getHasSpeaker() != null) room.setHasSpeaker(updateDto.getHasSpeaker());
        if (updateDto.getHasNetwork() != null) room.setHasNetwork(updateDto.getHasNetwork());
        if (updateDto.getHasMicrophone() != null) room.setHasMicrophone(updateDto.getHasMicrophone());
        if (updateDto.getHasWhiteboard() != null) room.setHasWhiteboard(updateDto.getHasWhiteboard());

        // 处理其他字段（类型、容量、价格等）
        if (updateDto.getType() != null) room.setType(updateDto.getType());
        if (updateDto.getCapacity() != null) room.setCapacity(updateDto.getCapacity());
        if (updateDto.getPricePerHour() != null) room.setPricePerHour(updateDto.getPricePerHour());
        if (updateDto.getOperatingStartTime() != null) room.setOperatingStartTime(updateDto.getOperatingStartTime());
        if (updateDto.getOperatingEndTime() != null) room.setOperatingEndTime(updateDto.getOperatingEndTime());
        if (updateDto.getStatus() != null) {
            // 只允许设置available和maintenance状态
            if (updateDto.getStatus() != RoomStatus.available && updateDto.getStatus() != RoomStatus.maintenance) {
                throw new IllegalArgumentException("只能设置会议室状态为available或maintenance，其他状态通过计算得出");
            }
            
            // 保护维护状态 - 只有明确指定维护状态才能覆盖
            if (room.getStatus() == RoomStatus.maintenance && updateDto.getStatus() != RoomStatus.maintenance) {
                throw new IllegalStateException(ErrorMessages.ROOM_IN_MAINTENANCE_CANNOT_CHANGE_STATUS);
            }
            room.setStatus(updateDto.getStatus());
        }
        if (updateDto.getDescription() != null) room.setDescription(updateDto.getDescription());

        MeetingRoom updatedRoom = meetingRoomRepository.save(room);
        return convertToDto(updatedRoom);
    }

    @Override
    @Transactional
    public MeetingRoomDto updateMeetingRoomStatus(Integer roomId, RoomStatus newStatus) {
        MeetingRoom room = meetingRoomRepository.findById(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));
        
        // 只允许设置available和maintenance状态
        if (newStatus != RoomStatus.available && newStatus != RoomStatus.maintenance) {
            throw new IllegalArgumentException("只能设置会议室状态为available或maintenance，其他状态通过计算得出");
        }
        
        // 保护维护状态 - 只有明确指定维护状态才能覆盖
        if (room.getStatus() == RoomStatus.maintenance && newStatus != RoomStatus.maintenance) {
            throw new IllegalStateException(ErrorMessages.ROOM_IN_MAINTENANCE_CANNOT_CHANGE_STATUS);
        }
        
        room.setStatus(newStatus);
        MeetingRoom updatedRoom = meetingRoomRepository.save(room);
        return convertToDto(updatedRoom);
    }

    //软删除会议室
    @Override
    @Transactional
    public void deleteMeetingRoom(Integer roomId) {
        MeetingRoom room = meetingRoomRepository.findById(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));

        // 检查是否已经被删除
        if (room.getDeleted()) {
            throw new IllegalStateException(ErrorMessages.MEETING_ROOM_ALREADY_DELETED);
        }

        // 检查是否有活跃的预订 - 现在主要依赖预订检查而非状态检查
        List<BookingStatus> activeStatuses = Arrays.asList(
                BookingStatus.pending_payment,
                BookingStatus.confirmed,
                BookingStatus.in_progress
        );
        boolean hasActiveBookings = bookingRepository.existsByRoomAndStatusInAndNotExpired(room, activeStatuses);
        if (hasActiveBookings) {
            throw new IllegalStateException(ErrorMessages.CANNOT_DELETE_ROOM_WITH_ACTIVE_BOOKINGS);
        }

        // 执行软删除
        room.setDeleted(true);
        room.setDeletedAt(LocalDateTime.now());
        // 注意：这里没有设置deletedBy，因为当前方法没有提供操作人信息
        // 如果需要记录操作人，应该在方法签名中添加操作人ID参数
        
        meetingRoomRepository.save(room);
    }

    @Override
    public Page<MeetingRoomDto> recommendMeetingRooms(MeetingRoomRecommendationDto recommendationDto, Pageable pageable) {
        Specification<MeetingRoom> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            // 排除已删除的会议室
            predicates.add(cb.equal(root.get("deleted"), false));

            // 只检查maintenance状态 - 维护中的会议室不能预订任何时间段
            predicates.add(cb.notEqual(root.get("status"), RoomStatus.maintenance));

            // 容量要求
            if (recommendationDto.getAttendeesCount() != null) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("capacity"), recommendationDto.getAttendeesCount()));
            }

            // 会议室类型偏好
            if (recommendationDto.getPreferredType() != null) {
                predicates.add(cb.equal(root.get("type"), recommendationDto.getPreferredType()));
            }

            // 设备要求
            if (Boolean.TRUE.equals(recommendationDto.getNeedProjector())) {
                predicates.add(cb.isTrue(root.get("hasProjector")));
            }
            if (Boolean.TRUE.equals(recommendationDto.getNeedSpeaker())) {
                predicates.add(cb.isTrue(root.get("hasSpeaker")));
            }
            if (Boolean.TRUE.equals(recommendationDto.getNeedNetwork())) {
                predicates.add(cb.isTrue(root.get("hasNetwork")));
            }
            if (Boolean.TRUE.equals(recommendationDto.getNeedMicrophone())) {
                predicates.add(cb.isTrue(root.get("hasMicrophone")));
            }
            if (Boolean.TRUE.equals(recommendationDto.getNeedWhiteboard())) {
                predicates.add(cb.isTrue(root.get("hasWhiteboard")));
            }

            // 检查指定时间段是否有冲突的预订
            if (recommendationDto.getStartDatetime() != null && recommendationDto.getEndDatetime() != null) {
                Subquery<Integer> subquery = query.subquery(Integer.class);
                Root<Booking> bookingRoot = subquery.from(Booking.class);
                subquery.select(bookingRoot.get("room").get("roomId"));

                // 时间重叠条件：检查是否存在与指定时间段重叠的预订
                Predicate timeOverlap = cb.and(
                        cb.lessThan(bookingRoot.get("startDatetime"), recommendationDto.getEndDatetime()),
                        cb.greaterThan(bookingRoot.get("endDatetime"), recommendationDto.getStartDatetime())
                );

                // 只考虑有效的预订状态（会造成时间冲突的状态）
                Predicate bookingStatusPredicate = bookingRoot.get("status").in(
                        BookingStatus.confirmed,
                        BookingStatus.pending_payment,
                        BookingStatus.in_progress
                );

                // 添加时间过滤：只考虑未结束的预订
                Predicate notExpiredPredicate = cb.greaterThan(bookingRoot.get("endDatetime"), cb.currentTimestamp());

                subquery.where(cb.and(
                        cb.equal(bookingRoot.get("room").get("roomId"), root.get("roomId")),
                        timeOverlap,
                        bookingStatusPredicate,
                        notExpiredPredicate  // 添加时间过滤条件
                ));

                // 排除有冲突预订的会议室 - 即只返回在指定时间段内可用的会议室
                predicates.add(cb.not(cb.exists(subquery)));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };

        Page<MeetingRoom> meetingRoomsPage = meetingRoomRepository.findAll(spec, pageable);
        
        // 为推荐的会议室计算在指定时间段的状态
        if (recommendationDto.getStartDatetime() != null && recommendationDto.getEndDatetime() != null) {
            // 获取所有会议室ID
            List<Integer> roomIds = meetingRoomsPage.getContent().stream()
                    .map(MeetingRoom::getRoomId)
                    .toList();

            // 查询指定时间段内的预订情况
            List<BookingStatus> validStatuses = Arrays.asList(
                    BookingStatus.confirmed,
                    BookingStatus.pending_payment,
                    BookingStatus.in_progress
            );

            List<Booking> overlappingBookings = bookingRepository.findPeriodBookings(
                    roomIds,
                    recommendationDto.getStartDatetime(),
                    recommendationDto.getEndDatetime(),
                    validStatuses
            );

            // 由于已经过滤掉了有冲突的会议室，这里的overlappingBookings应该为空
            // 但为了保险起见，还是进行状态计算
            Map<Integer, Booking> earliestOverlappingBookings = overlappingBookings.stream()
                    .collect(Collectors.toMap(
                            b -> b.getRoom().getRoomId(),
                            b -> b,
                            (existing, replacement) -> existing.getStartDatetime().isBefore(replacement.getStartDatetime()) ?
                                    existing : replacement
                    ));

            // 设置计算状态
            for (MeetingRoom room : meetingRoomsPage.getContent()) {
                Booking earliestBooking = earliestOverlappingBookings.get(room.getRoomId());
                room.setCalculatedStatus(calculateStatus(room, earliestBooking));
            }
        }

        return meetingRoomsPage.map(this::convertToDto);
    }

    @Override
    public List<MeetingRoomDto> getRoomsByStatus(RoomStatus status) {
        if (status == RoomStatus.available || status == RoomStatus.maintenance) {
            // 对于数据库存储的状态，直接查询
            return meetingRoomRepository.findByStatus(status).stream()
                    .map(this::convertToDto)
                    .collect(Collectors.toList());
        } else {
            // 对于计算状态（locked, booked, in_use），需要查询所有非维护状态的会议室并计算状态
            List<MeetingRoom> availableRooms = meetingRoomRepository.findByStatus(RoomStatus.available);
            List<MeetingRoomDto> result = new ArrayList<>();
            
            if (!availableRooms.isEmpty()) {
                // 批量查询当前时间点的所有预订，避免N+1查询
                List<Integer> roomIds = availableRooms.stream()
                        .map(MeetingRoom::getRoomId)
                        .collect(Collectors.toList());
                
                List<BookingStatus> validStatuses = Arrays.asList(
                        BookingStatus.confirmed,
                        BookingStatus.pending_payment,
                        BookingStatus.in_progress
                );
                
                LocalDateTime now = LocalDateTime.now();
                List<Booking> allOverlappingBookings = bookingRepository.findPeriodBookings(
                        roomIds,
                        now,
                        now.plusMinutes(1), // 查询当前时间点
                        validStatuses
                );
                
                // 按会议室ID分组，找到每个会议室的最早预订
                Map<Integer, Booking> earliestBookingByRoom = allOverlappingBookings.stream()
                        .collect(Collectors.toMap(
                                b -> b.getRoom().getRoomId(),
                                b -> b,
                                (existing, replacement) -> existing.getStartDatetime().isBefore(replacement.getStartDatetime()) ?
                                        existing : replacement
                        ));
                
                // 计算每个会议室的状态并过滤
                for (MeetingRoom room : availableRooms) {
                    Booking earliestBooking = earliestBookingByRoom.get(room.getRoomId());
                    RoomStatus calculatedStatus = calculateStatus(room, earliestBooking);
                    if (calculatedStatus == status) {
                        room.setCalculatedStatus(calculatedStatus);
                        result.add(convertToDto(room));
                    }
                }
            }
            
            return result;
        }
    }

    /**
     * 员工对相应状态的会议室进行状态变更，并同步更新关联订单状态
     */
    @Override
    @Transactional
    public MeetingRoomDto changeRoomStatus(Integer roomId, RoomStatus newRoomStatus, String roomConditionNotes, Integer employeeId) {
        // 验证员工
        User employee = userRepository.findById(employeeId)
                .orElseThrow(() -> new EntityNotFoundException("找不到员工ID: " + employeeId));
        if (employee.getRole() != UserRole.employee && employee.getRole() != UserRole.admin) {
            throw new SecurityException("用户没有设置维护状态的权限");
        }
        // 1. 查询会议室
        MeetingRoom room = meetingRoomRepository.findById(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));

        // 只允许设置available和maintenance状态
        if (newRoomStatus != RoomStatus.available && newRoomStatus != RoomStatus.maintenance) {
            throw new IllegalArgumentException("只能设置会议室状态为available或maintenance，其他状态通过计算得出");
        }

        RoomStatus oldRoomStatus = room.getStatus();
//        // 2. 使用Specification查询当前关联的活跃订单（如果存在）
//        Booking activeBooking = null;
//        if (oldRoomStatus == RoomStatus.booked || oldRoomStatus == RoomStatus.in_use) {
//            // 创建查询条件：roomId + 状态为confirmed或in_progress
//            BookingQueryDto queryDto = new BookingQueryDto();
//            queryDto.setRoomId(roomId);
//            queryDto.setStatusList(Arrays.asList(BookingStatus.confirmed, BookingStatus.in_progress));
//
//            // 执行查询，取第一条结果
//            Specification<Booking> spec = BookingSpecification.findByCriteria(queryDto);
//            activeBooking = bookingRepository.findOne(spec)
//                    .orElse(null);
//        }
//
//        // 3. 根据状态变更规则更新订单状态和检查时间
//        if (activeBooking != null) {
//            if (newRoomStatus == RoomStatus.in_use && oldRoomStatus == RoomStatus.booked) {
//                // 会议室: booked -> in_use , 订单: confirmed -> in_progress
//                activeBooking.setStatus(BookingStatus.in_progress);
//                activeBooking.setCheckInTime(LocalDateTime.now());
//                activeBooking.setCheckedBy(employee);
//            } else if ((newRoomStatus == RoomStatus.available || newRoomStatus == RoomStatus.maintenance)
//                    && oldRoomStatus == RoomStatus.in_use) {
//                // 会议室: in_use -> available/maintenance , 订单: in_progress -> completed
//                activeBooking.setStatus(BookingStatus.completed);
//                activeBooking.setCheckOutTime(LocalDateTime.now());
//                activeBooking.setCheckedBy(employee);
//                activeBooking.setRoomConditionNotes(roomConditionNotes);
//            }
//
//            bookingRepository.save(activeBooking);
//        }

        // 更新会议室状态和备注
        // 注意：此方法是员工/管理员手动状态变更，允许覆盖维护状态
        // 但需要确保业务逻辑合理，比如从维护状态变为其他状态时应该是维护完成
        room.setStatus(newRoomStatus);
        // 生成设备支持描述
        String equipmentSupport = generateEquipmentSupportDescription(room);

        // 当从maintenance变为available时，自动设置设备支持描述
        if (oldRoomStatus == RoomStatus.maintenance && newRoomStatus == RoomStatus.available) {
            room.setDescription("支持：" + equipmentSupport);
        } else if (roomConditionNotes != null && !roomConditionNotes.isEmpty()) {
            // 其他情况使用传入的备注
            room.setDescription(roomConditionNotes);
        }


        // 5. 保存更新并返回
        MeetingRoom updatedRoom = meetingRoomRepository.save(room);
        return convertToDto(updatedRoom);
    }

    /**
     * 根据会议室设备生成支持的设备描述
     */
    private String generateEquipmentSupportDescription(MeetingRoom room) {
        List<String> supportedEquipment = new ArrayList<>();

        if (Boolean.TRUE.equals(room.getHasProjector())) {
            supportedEquipment.add("投影仪");
        }
        if (Boolean.TRUE.equals(room.getHasSpeaker())) {
            supportedEquipment.add("音响");
        }
        if (Boolean.TRUE.equals(room.getHasNetwork())) {
            supportedEquipment.add("网络");
        }
        if (Boolean.TRUE.equals(room.getHasMicrophone())) {
            supportedEquipment.add("麦克风");
        }
        if (Boolean.TRUE.equals(room.getHasWhiteboard())) {
            supportedEquipment.add("白板");
        }

        return String.join("、", supportedEquipment);
    }

    // 管理员专用：带操作人ID的软删除方法
    @Override
    @Transactional
    public void deleteMeetingRoom(Integer roomId, Integer adminId) {
        // 验证管理员权限
        User admin = userRepository.findById(adminId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.USER_NOT_FOUND, adminId)));
        if (admin.getRole() != UserRole.admin) {
            throw new SecurityException("只有管理员可以删除会议室");
        }

        MeetingRoom room = meetingRoomRepository.findById(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));

        // 检查是否已经被删除
        if (room.getDeleted()) {
            throw new IllegalStateException(ErrorMessages.MEETING_ROOM_ALREADY_DELETED);
        }

        // 注释：现在主要依赖预订检查而非状态检查

        // 检查是否有活跃的预订
        List<BookingStatus> activeStatuses = Arrays.asList(
                BookingStatus.pending_payment,
                BookingStatus.confirmed,
                BookingStatus.in_progress
        );
        boolean hasActiveBookings = bookingRepository.existsByRoomAndStatusInAndNotExpired(room, activeStatuses);
        if (hasActiveBookings) {
            throw new IllegalStateException(ErrorMessages.CANNOT_DELETE_ROOM_WITH_ACTIVE_BOOKINGS);
        }

        // 执行软删除
        room.setDeleted(true);
        room.setDeletedAt(LocalDateTime.now());
        room.setDeletedBy(admin);
        
        meetingRoomRepository.save(room);
    }

    // 管理员专用：查看已删除的会议室
    @Override
    public Page<MeetingRoomDto> getDeletedMeetingRooms(Pageable pageable) {
        Page<MeetingRoom> deletedRooms = meetingRoomRepository.findDeleted(pageable);
        return deletedRooms.map(this::convertToDto);
    }

    // 管理员专用：恢复删除的会议室
    @Override
    @Transactional
    public MeetingRoomDto restoreMeetingRoom(Integer roomId, Integer adminId) {
        // 验证管理员权限
        User admin = userRepository.findById(adminId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.USER_NOT_FOUND, adminId)));
        if (admin.getRole() != UserRole.admin) {
            throw new SecurityException("只有管理员可以恢复会议室");
        }

        // 使用包含已删除记录的查询方法
        MeetingRoom room = meetingRoomRepository.findByIdIncludeDeleted(roomId)
                .orElseThrow(() -> new EntityNotFoundException(String.format(ErrorMessages.MEETING_ROOM_NOT_FOUND, roomId)));

        // 检查是否已被删除
        if (!room.getDeleted()) {
            throw new IllegalStateException(ErrorMessages.MEETING_ROOM_NOT_DELETED);
        }

        // 检查恢复后的名称是否冲突
        Optional<MeetingRoom> existingRoom = meetingRoomRepository.findByName(room.getName());
        if (existingRoom.isPresent()) {
            throw new IllegalArgumentException(String.format(ErrorMessages.ROOM_NAME_CONFLICT, room.getName()));
        }

        // 执行恢复
        room.setDeleted(false);
        room.setDeletedAt(null);
        room.setDeletedBy(null);
        
        MeetingRoom restoredRoom = meetingRoomRepository.save(room);
        return convertToDto(restoredRoom);
    }

    private MeetingRoomDto convertToDto(MeetingRoom meetingRoom) {
        MeetingRoomDto dto = new MeetingRoomDto();
        BeanUtils.copyProperties(meetingRoom, dto);
        if (meetingRoom.getCalculatedStatus() != null) {
            dto.setStatus(meetingRoom.getCalculatedStatus());
        } else {
            dto.setStatus(meetingRoom.getStatus());
        }
        return dto;
    }
}